package com.googlecode.lohr.parser.combinators;

import java.lang.reflect.Field;
import java.util.Arrays;

import com.googlecode.lohr.parser.combinators.matcher.AnyStringMatcher;
import com.googlecode.lohr.parser.combinators.matcher.ChoiceMatcher;
import com.googlecode.lohr.parser.combinators.matcher.ExcludingMatcher;
import com.googlecode.lohr.parser.combinators.matcher.LongestMatcher;
import com.googlecode.lohr.parser.combinators.matcher.Matcher;
import com.googlecode.lohr.parser.combinators.matcher.RangeMatcher;
import com.googlecode.lohr.parser.combinators.matcher.RepetitionMatcher;
import com.googlecode.lohr.parser.combinators.matcher.SequenceMatcher;
import com.googlecode.lohr.parser.combinators.matcher.StringMatcher;

public class Grammar {
	
	protected final int max= Integer.MAX_VALUE;
	
	protected StringMatcher string(final String string)
	{
		return new StringMatcher(string);
	}
	protected StringMatcher str(final String string)
	{
		return new StringMatcher(string);
	}
	protected StringMatcher string(final char c)
	{
		return new StringMatcher(""+c);
	}
	protected StringMatcher str(final char c)
	{
		return new StringMatcher(""+c);
	}

	protected Matcher range(final char from, final char to)
	{
		return new RangeMatcher(to, from);
	}

	protected Matcher sequence(final Matcher... matchers)
	{
		return new SequenceMatcher(matchers);
	}
	protected Matcher seq(final Matcher... matchers)
	{
		return new SequenceMatcher(matchers);
	}

	protected ChoiceMatcher choice(final Matcher... matchers)
	{
		return new ChoiceMatcher(matchers);
	}
	protected ChoiceMatcher cho(final Matcher... matchers)
	{
		return new ChoiceMatcher(matchers);
	}
	protected ChoiceMatcher lchoice(final Matcher... matchers)
	{
		return new LongestMatcher(matchers);
	}
	protected ChoiceMatcher lcho(final Matcher... matchers)
	{
		return new LongestMatcher(matchers);
	}
	
	protected Matcher longest(final Matcher... matchers)
	{
		return new LongestMatcher(matchers);
	}
	protected Matcher lng(final Matcher... matchers)
	{
		return new LongestMatcher(matchers);
	}
	
	protected Matcher anyChar()
	{
		return new AnyStringMatcher(1);
	}
	
	protected Matcher excluding(final Matcher matcher, final Matcher... filters)
	{
		return new ExcludingMatcher(matcher, filters);
	}
	protected Matcher exc(final Matcher matcher, final Matcher... filters)
	{
		return new ExcludingMatcher(matcher, filters);
	}

	protected Matcher repeat(final int min, final int max, final Matcher matcher)
	{
		return new RepetitionMatcher(min, max, RepetitionMatcher.Type.SEQUENCE, matcher);
	}
	protected Matcher rep(final int min, final int max, final Matcher matcher)
	{
		return new RepetitionMatcher(min, max, RepetitionMatcher.Type.SEQUENCE, matcher);
	}
	protected Matcher rep(final Matcher matcher)
	{
		return new RepetitionMatcher(0, max, RepetitionMatcher.Type.SEQUENCE, matcher);
	}
	protected Matcher lrepeat(final int min, final int max, final Matcher matcher)
	{
		return new LongestMatcher(new RepetitionMatcher(min, max, RepetitionMatcher.Type.SEQUENCE, matcher));
	}
	protected Matcher lrep(final int min, final int max, final Matcher matcher)
	{
		return new LongestMatcher(new RepetitionMatcher(min, max, RepetitionMatcher.Type.SEQUENCE, matcher));
	}
	protected Matcher lrep(final Matcher matcher)
	{
		return new LongestMatcher(new RepetitionMatcher(0, max, RepetitionMatcher.Type.SEQUENCE, matcher));
	}

	// ============================================================================================
	// === OPTIONAL MATCHERS
	// ============================================================================================

	protected Matcher optional(final Matcher matcher)
	{
		return choice(matcher, string(""));
	}
	protected Matcher opt(final Matcher matcher)
	{
		return choice(matcher, string(""));
	}

	protected <T> Matcher[] tail(final Matcher[] array)
	{
		return Arrays.asList(array).subList(1, array.length).toArray(new Matcher[] {});
	}
	
	
	protected void init() {
		generateElementLabels();
	}
	
	private void generateElementLabels() {
		Class<? extends Grammar> grammarClass= getClass();
		Field[] fields= grammarClass.getFields();
		for (Field field:fields) {
			if (!Matcher.class.isAssignableFrom(field.getType()))
				continue;
			field.setAccessible(true);
			Matcher matcher= null;
			try { 
				matcher= (Matcher)field.get(this);
			}
			catch (Exception x) {
				x.printStackTrace();
				continue;
			}
			matcher.setLabel(field.getName());
		}
		
	}
	
	
}
